-- Util
require 'button'
require 'bullet'
require 'player'
require 'menu'
require 'util'

local randomOffset = 0

local function randomColor()
    math.randomseed(tostring(os.time()):reverse():sub(1, 6) + randomOffset)
    randomOffset = math.random(1000000)
    return {math.random(), math.random(), math.random()}
end

-- Menu
local game_state = 'play'
local menu = Menu:new()
local menuBtn = {
    {
        text = 'exit',
        w = menu.w / 5 * 3,
        h = 50,
        x = menu.x + menu.w / 2 - menu.w / 5 * 3 / 2,
        y = menu.y + (menu.h - 100) / 3 + 25,
        color = color({255, 159, 26}),
        func = function()
            love.event.quit()
        end
    },
    {
        text = 'cancel',
        w = menu.w / 5 * 3,
        h = 50,
        x = menu.x + menu.w / 2 - menu.w / 5 * 3 / 2,
        y = menu.y + 75 + (menu.h - 100) / 3 * 2,
        color = color({255, 159, 26}),
        func = function()
            game_state = 'play'
        end
    }
}

-- Main Border

local border = {
    t = sh / 6,
    b = sh / 6,
    l = 0,
    r = 0
}

-- Timers

local fireTimer = 0
local dashTimer = 0
local blinkTimer = 0
local changeTimer = 0

-- Entity Storage
local bullets = {}
local buttons = {}

-- Player Object
local player = Player:new()

-- Buttons

local btnw = (sw - border.r - border.l) / 8
local restw = (sw - border.r - border.l - btnw * 4) / 5
local margin = btnw + restw

local buttons_decl = {
    {
        text = 'menu',
        x = restw,
        y = border.b / 2,
        w = btnw,
        h = 50,
        color = color({36, 121, 158}),
        func = function()
            game_state = 'menu'
        end
    },
    {
        text = 'fire',
        x = restw,
        y = sh - border.b / 2,
        w = btnw,
        h = 50,
        color = color({255, 0, 0}),
        func = function(_, dt)
            fireTimer = fireTimer - dt
            if fireTimer < 0 then
                fireTimer = player.fireCD
                local newBullet = Bullet:new(player)
                table.insert(bullets, newBullet)
            end
        end
    },
    {
        text = 'dash',
        x = margin * 1 + restw,
        y = sh - border.b / 2,
        w = btnw,
        h = 50,
        color = color({0, 255, 255}),
        func = function()
            if not player.isDashed then
                player.isDashed = true
                dashTimer = player.dashCD
                player.speed = player.dashedSpeed
            end
        end
    },
    {
        text = 'blink',
        x = margin * 2 + restw,
        y = sh - border.b / 2,
        w = btnw,
        h = 50,
        color = color({255, 255, 0}),
        func = function(_, dt)
            blinkTimer = blinkTimer - dt
            if blinkTimer < 0 then
                blinkTimer = player.blinkCD
                if player.rot == 0 then
                    player.y = player.y - player.blinkDist
                    updateAABB()
                    if checkCollision(player) then
                        player.y = border.t + player.h / 2
                    end
                elseif player.rot == -pi / 2 then
                    player.x = player.x - player.blinkDist
                    updateAABB()
                    if checkCollision(player) then
                        player.x = border.l + player.w / 2
                    end
                elseif player.rot == pi then
                    player.y = player.y + player.blinkDist
                    updateAABB()
                    if checkCollision(player) then
                        player.y = sh - border.b - player.h / 2
                    end
                elseif player.rot == pi / 2 then
                    player.x = player.x + player.blinkDist
                    updateAABB()
                    if checkCollision(player) then
                        player.x = sw - border.r - player.w / 2
                    end
                end
                updateAABB()
            end
        end
    },
    {
        text = 'change',
        x = margin * 3 + restw,
        y = sh - border.b / 2,
        w = btnw,
        h = 50,
        color = color({255, 0, 255}),
        func = function(_, dt)
            changeTimer = changeTimer - dt
            if changeTimer < 0 then
                changeTimer = player.changeCD
                player.color = randomColor()
            end
        end
    }
}

local function ui()
    -- draw_box
    lg.setBackgroundColor({1, 1, 1})
    lg.setColor({.7, .7, .7})
    lg.rectangle('fill', 0, 0, sw, border.t)
    lg.setColor({0, 0, 0})
    lg.rectangle('line', 0, 0, sw, border.t)
    lg.setColor(color({112, 194, 180}))
    lg.rectangle('fill', 0, sh - border.b, sw, border.b)
    lg.setColor({0, 0, 0})
    lg.rectangle('line', 0, sh - border.b, sw, border.b)
    lg.setColor({1, 1, 1})
end

function checkCollision(obj)
    if
        obj.aabb.x < border.l or obj.aabb.x + obj.w > sw - border.r or obj.aabb.y < border.t or
            obj.aabb.y + obj.h > sh - border.b
     then
        return true
    end
end

function updateAABB()
    player.aabb.x = player.x - player.w / 2
    player.aabb.y = player.y - player.h / 2
end

local function keyControl(dt)
    local down = love.keyboard.isDown
    if down('w') then
        player.rot = 0
        player.y = player.y - player.speed * dt
        updateAABB()
        if checkCollision(player) then
            player.y = border.t + player.h / 2
        end
    elseif down('a') then
        player.rot = -pi / 2
        player.x = player.x - player.speed * dt
        updateAABB()
        if checkCollision(player) then
            player.x = border.l + player.w / 2
        end
    elseif down('s') then
        player.rot = pi
        player.y = player.y + player.speed * dt
        updateAABB()
        if checkCollision(player) then
            player.y = sh - border.b - player.h / 2
        end
    elseif down('d') then
        player.rot = pi / 2
        player.x = player.x + player.speed * dt
        updateAABB()
        if checkCollision(player) then
            player.x = sw - border.r - player.w / 2
        end
    end
    updateAABB()
end

function love.load()
    player.aabb.x = player.x - player.w / 2
    player.aabb.y = player.y - player.h / 2

    for _, v in ipairs(buttons_decl) do
        local newBtn = Button:new(v.text, v.x, v.y, v.w, v.h, v.color)
        if v.func ~= nil then
            newBtn:onClick(v.func)
        end
        table.insert(buttons, newBtn)
    end

    for _, v in ipairs(menuBtn) do
        menu:addBtn(v.text, v.x, v.y, v.w, v.h, v.color,v.func)
    end
end

function love.update(dt)
    if game_state == 'play' then
        keyControl(dt)
        for _, v in ipairs(buttons) do
            v:update(dt)
        end
        for i = #bullets, 1, -1 do
            local go = bullets[i]
            go:update(dt, border.l, sw - border.r, border.t, sh - border.b)
            if go.destroyed then
                table.remove(bullets, i)
            end
        end
        if player.isDashed then
            if dashTimer > 0 then
                dashTimer = dashTimer - dt
            else
                player.isDashed = false
                player.speed = player.normalSpeed
            end
        end
    elseif game_state == 'menu' then
        menu:update(dt)
    end
end

function love.draw()
    ui()
    player:draw()
    if debug then
        lg.setColor({1, 1, 0})
        lg.circle('fill', player.x, player.y, 5)
        lg.setColor({1, 0, 0})
        lg.circle('line', player.x, player.y, player.r)
        lg.setColor({1, 1, 1})
    end
    for _, v in ipairs(bullets) do
        v:draw()
    end
    for _, v in ipairs(buttons) do
        v:draw()
    end
    if game_state == 'menu' then
        menu:draw()
    end
end
